import 'dart:convert';

import 'package:imperius_insights/portal/channels/factory.dart';
import 'package:imperius_insights/portal/channels/web.dart';

import '../math.dart';
import '../typings.dart';

class _ConnectivityException implements Exception {}

class _DataException implements Exception {}

Future<HealthCheckResult> healthCheck(
    HealthCheckRequest healthCheckRequest) async {
  var isRoundOne = true;
  var startupWithConnectivityIssue = false;
  final summary = await avg(() async {
    if (startupWithConnectivityIssue) throw _ConnectivityException();
    final isRoundOneSnapshot = isRoundOne;
    isRoundOne = false;
    final channel = Channels.shared<WebChannel>(ChannelType.Web);
    String response;
    try {
      response = await channel.invoke(
          target: healthCheckRequest.callableTarget,
          params: healthCheckRequest.params);
    } catch (ex) {
      if (isRoundOneSnapshot) startupWithConnectivityIssue = true;
      throw _ConnectivityException();
    }
    try {
      if (healthCheckRequest.dataFormat == EnumDataFormat.JSON)
        jsonDecode(response);
    } catch (ex) {
      throw _DataException();
    }
  })(healthCheckRequest.sampleTimes);
  final hcr = HealthCheckResult(healthCheckRequest,
      summary: summary,
      errorTypes: Set<EnumErrorType>(),
      exceptions: summary.exceptions);
  if (summary.exceptions != null) {
    if (summary.exceptions.indexWhere((ex) => ex is _ConnectivityException) >=
        0) {
      hcr.errorTypes.add(EnumErrorType.UnableConnect);
    }
    if (summary.exceptions.indexWhere((ex) => ex is _DataException) >= 0) {
      hcr.errorTypes.add(EnumErrorType.ServiceError);
    }
  }
  if (summary.availableRatio > 0 && summary.availableRatio < 0.9) {
    hcr.errorTypes.add(EnumErrorType.Instability);
  }
  return hcr;
}
